#ifndef __WIZ_DATATYPE_ARRAY_HPP__SHANHAOBO_19800429__
#define __WIZ_DATATYPE_ARRAY_HPP__SHANHAOBO_19800429__

#include <vector>
#include <algorithm>

#include "../../Base/WizBase.hpp"

#include "./WizDataTypeForEach.hpp"

#define WIZ_DECLARE_ARRAY(t)                                \
    namespace Array                                         \
    {                                                       \
    WIZ_DECLARE(::Wiz::Array::Type<t>);                     \
    typedef Type::tIterator         tIterator;              \
    typedef Type::tIteratorConst    tIteratorConst;         \
    typedef Type::tForEach          tForEach;               \
    typedef Type::tForEachConst     tForEachConst;          \
    typedef Type::tForEachIter      tForEachIter;           \
    }

/// #define t Size, Type
#define WIZ_DECLARE_STATICARRAY(l, t)                       \
    namespace StaticArray                                   \
    {                                                       \
    WIZ_DECLARE(::Wiz::StaticArray::Type<l WIZ_COMMA t>);   \
    typedef Type::tIterator         tIterator;              \
    typedef Type::tIteratorConst    tIteratorConst;         \
    }

namespace Wiz
{
    namespace Array
    {
        template<class ElementT>
        struct Type : private ::std::vector<ElementT>
        {
            //////////////////////////////////////////////////////////////////////////
            typedef Type                                        tThis;
            typedef ElementT                                    tElement;
            typedef const ElementT                              tElementConst;
            typedef tElement*                                   tElementPtr;
            typedef tElementConst*                              tConstElementPtr;
            typedef ::std::vector<ElementT>                     tSuper;
            typedef typename tSuper::iterator                   tIterator;
            typedef typename tSuper::const_iterator             tIteratorConst;
            typedef typename tSuper::iterator::value_type       tValue;
            typedef typename tSuper::const_iterator::value_type tValueConst;
            typedef typename tSuper::reference                  tReference;
            typedef typename tSuper::const_reference            tReferenceConst;
            typedef typename tSuper::size_type                  tSize;
            typedef typename tSuper::reverse_iterator           tReverseIterator;
            typedef typename tSuper::const_reverse_iterator     tConstReverseIterator;
            //////////////////////////////////////////////////////////////////////////
            typedef ::Wiz::ForEach::Type<::Wiz::Array::Type<ElementT>>         tForEach;
            typedef ::Wiz::ConstForEach::Type<::Wiz::Array::Type<ElementT>>    tForEachConst;
            typedef ::Wiz::ForEachIter::Type<::Wiz::Array::Type<ElementT>>     tForEachIter;
            //////////////////////////////////////////////////////////////////////////
        public:
			Type() : tSuper(){}
			Type(const tSuper& InSuper) : tSuper(InSuper){}

            Type(tSize Reserved) : tSuper(Reserved){}
            Type(tSize Reserved, tElementConst Ele) : tSuper(Reserved, Ele){}
        public:
            tIterator Begin()
            {
                return tSuper::begin();
            }

            tIteratorConst Begin() const
            {
                return tSuper::begin();
            }

            tIterator End()
            {
                return tSuper::end();
            }

            tIteratorConst End() const
            {
                return tSuper::end();
            }

            tReverseIterator RBegin()
            {
                return tSuper::rbegin();
            }

            tConstReverseIterator RBegin() const
            {
                return tSuper::rbegin();
            }

            tReverseIterator REnd()
            {
                return tSuper::rend();
            }

            tConstReverseIterator REnd() const
            {
                return tSuper::rend();
            }

            ///-----------------------///

            ::Wiz::Size::Type Size() const
            {
                return ::Wiz::Cast::Static<::Wiz::Size::Type>(tSuper::size());
            }

            ::Wiz::Void::Type Resize(::Wiz::Size::In NewSZ)
            {
                return tSuper::resize(NewSZ);
            }

            ::Wiz::Void::Type Clear()
            {
                tSuper::clear();
            }

            tIterator Erase(tIterator itr)
            {
                return tSuper::erase(itr);
            }

            ::Wiz::Void::Type Remove(const ElementT& v)
            {
                struct tRemoveInnerStruct
                {
                    const ElementT m_Ele;
                    tRemoveInnerStruct(const ElementT& InEle) : m_Ele(InEle){}

                    bool operator() (const ElementT& InEle)
                    {
                        return m_Ele == InEle;
                    }
                };

                tRemoveInnerStruct RIS(v);

                RemoveIf(RIS);
            }

            ///-----------------------///

            template<class FuncT>
            tIterator FindIf(FuncT Func)
            {
                return ::std::find_if(tSuper::begin(), tSuper::end(), Func);
            }

            template<class FuncT>
            ::Wiz::Void::Type RemoveIf(FuncT Func)
            {
                tSuper::iterator newend = ::std::remove_if(tSuper::begin(), tSuper::end(), Func);
                tSuper::erase(newend, tSuper::end());
            }

            ///-----------------------///

            ::Wiz::Void::Type PushBack(const ElementT& v)
            {
                tSuper::push_back(v);
            }

            ::Wiz::Void::Type PopBack()
            {
                tSuper::pop_back();
            }

            tReference GetLast()
            {
                return tSuper::back();
            }

            tReferenceConst GetLast() const
            {
                return tSuper::back();
            }

            tReferenceConst Front() const
            {
                return tSuper::front();
            }

            tReference Front()
            {
                return tSuper::front();
            }

            tReferenceConst Back() const
            {
                return tSuper::back();
            }

            tReference Back()
            {
                return tSuper::back();
            }

            ::Wiz::Size::Type Capacity()
            {
                return tSuper::capacity();
            }

            ::Wiz::Void::Type Reserve(::Wiz::Size::In SZ)
            {
                tSuper::reserve(SZ);
            }

            tReference operator[](tSize Pos)
            {
                return tSuper::operator [](Pos);
            }
            tReferenceConst operator[](tSize Pos) const
            {
                return tSuper::operator [](Pos);
            }
        public:
            tElementPtr GetBuffer()
            {
                return &(tSuper::operator [](0));
            }

            tConstElementPtr GetBuffer() const
            {
                return &(tSuper::operator [](0));
            }
        };
    } /// end of namespace Array

    namespace StaticArray
    {
        template<::Wiz::Size::Type ISize, class ElementT>
        class Type
        {
        public:
            enum
            {
                eSize = ISize,
            };
            typedef ElementT            tElement;
            typedef tElement*           tElementPtr;
            typedef const tElement*     tElementConstPtr;

            typedef tElement            tElementBuffer[eSize];

            typedef Type                tThis;

        public:
            typedef tElementPtr         tIterator;
            typedef tElementConstPtr    tIteratorConst;

        protected:
            tElementBuffer              m_Elements;
        public:
            WIZ_INLINE tElement& operator[](::Wiz::UInt::In idx)
            {
                WIZ_ASSERT(idx < eSize);

                return m_Elements[idx];
            }
            WIZ_INLINE const tElement& operator[](::Wiz::UInt::In idx) const
            {
                WIZ_ASSERT(idx < eSize);

                return m_Elements[idx];
            }
        public:
            WIZ_INLINE tIterator Get(::Wiz::UInt::In idx)
            {
                WIZ_ASSERT(idx < eSize);

                return &(m_Elements[idx]);
            }

            WIZ_INLINE tIteratorConst Get(::Wiz::UInt::In idx) const
            {
                WIZ_ASSERT(idx < eSize);

                return &(m_Elements[idx]);
            }
        public:
            WIZ_INLINE tIterator Begin()
            {
                return Get(0);
            }
            WIZ_INLINE tIteratorConst Begin() const
            {
                return Get(0);
            }
            WIZ_INLINE tIterator End()
            {
                return Get(eSize - 1);
            }
            WIZ_INLINE tIteratorConst End() const
            {
                return Get(eSize - 1);
            }
        public:
            WIZ_INLINE ::Wiz::Size::Type ESize() const
            {
                return sizeof(tElement);
            }
            WIZ_INLINE ::Wiz::Size::Type Size() const
            {
                return eSize;
            }
        public:
            WIZ_INLINE tThis& operator=(const tThis& InOther)
            {
                ::Wiz::Memory::Copy<tElementBuffer>(m_Elements, InOther.m_Elements);

                return *this;
            }
        public:
            Type()
            {
            }
            Type(const tElement& InEle)
            {
                for (::Wiz::UIndex::Type i = 0; i < eSize; ++i)
                {
                    m_Elements[i] = InEle;
                }
            }
            Type(const tElementBuffer& InEleBuff)
            {
                ::Wiz::Memory::Copy<tElementBuffer>(m_Elements, InEleBuff);
            }
            Type(const tThis& InOther)
            {
                ::Wiz::Memory::Copy<tElementBuffer>(m_Elements, InOther.m_Elements);
            }
        };
    }

    namespace StaticArrayProxy
    {
        template<class ElementT>
        class Type
        {
            typedef ElementT            tElement;
            typedef tElement*           tElementPtr;
            typedef const tElement*     tElementConstPtr;
            typedef union
            {
                ::Wiz::Byte::Ptr        BytePtr;
                tElementPtr             ElementPtr;
            } tUnionPtr;
            typedef union
            {
                ::Wiz::Byte::ConstPtr   BytePtr;
                tElementConstPtr        ElementPtr;
            } tUnionConstPtr;
        protected:
            tUnionPtr                   m_Ptr;
            ::Wiz::Size::Type           m_Size;
        public:
            typedef tElementPtr         tIterator;
            typedef tElementConstPtr    tIteratorConst;
        public:
            tIterator Get(::Wiz::UInt::In idx)
            {
                WIZ_ASSERT(idx < this->m_Size);

                tUnionPtr UPtr;
                UPtr.BytePtr = this->m_Ptr.BytePtr + sizeof(ElementT) * idx;

                return UPtr.ElementPtr;
            }
            tIteratorConst Get(::Wiz::UInt::In idx) const
            {
                WIZ_ASSERT(idx < this->m_Size);

                tUnionConstPtr UPtr;
                UPtr.BytePtr = this->m_Ptr.BytePtr + sizeof(ElementT) * idx;

                return UPtr.ElementPtr;
            }
        public:
            tElement& operator[](::Wiz::UInt::In idx)
            {
                return *(this->Get(idx));
            }
            const tElement& operator[](::Wiz::UInt::In idx) const
            {
                return *(this->Get(idx));
            }
            tIterator Begin()
            {
                return m_Ptr.ElementPtr;
            }
            tIteratorConst Begin() const
            {
                return m_Ptr.ElementPtr;
            }
            tIterator End()
            {
                tUnionPtr UPtr;
                UPtr.BytePtr = this->m_Ptr.BytePtr + sizeof(ElementT) * this->m_Size;

                return UPtr.ElementPtr;
            }
            tIteratorConst End() const
            {
                tUnionConstPtr UPtr;
                UPtr.BytePtr = this->m_Ptr.BytePtr + sizeof(ElementT) * this->m_Size;

                return UPtr.ElementPtr;
            }
        public:
            ::Wiz::Size::Type ESize() const
            {
                return sizeof(tElement);
            }
            ::Wiz::Size::Type Size() const
            {
                return this->m_Size;
            }
            ::Wiz::Void::Type Attach(tElementPtr dp, ::Wiz::Size::In sz)
            {
                this->m_Ptr.ElementPtr  = dp;
                this->m_Size            = sz;
            }
            ::Wiz::Void::Type Attach(::Wiz::Void::Ptr dp, ::Wiz::Size::In sz)
            {
                this->m_Ptr.ElementPtr  = ::Wiz::Cast::Static<tElementPtr>(dp);
                this->m_Size            = sz;
            }
            ::Wiz::Bool::Type IsValid() const
            {
                return ::Wiz::IsValidPtr(this->m_Ptr) && (this->m_Size > 0);
            }
        public:
            Type() : m_Size(0)
            {
                m_Ptr.BytePtr = WIZ_NULLPTR; 
            }
            Type(tElementPtr dp, ::Wiz::Size::In sz) : m_Size(sz)
            {
                m_Ptr.ElementPtr = dp;
            }
            Type(::Wiz::Void::Ptr dp, ::Wiz::Size::In sz) : m_Size(sz)
            {
                m_Ptr.ElementPtr = ::Wiz::Cast::Static<tElementPtr>(dp);
            }
        }; /// end of class Type
    } /// end of namespace StaticArray
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
} /// end of namespace Wiz

#endif /*__WIZ_DATATYPE_ARRAY_HPP__SHANHAOBO_19800429__*/
